/**
* @file utils.h
*
* Copyright (C) 2020. Huawei Technologies Co., Ltd. All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#pragma once
#include <iostream>
#include <unistd.h>
#include <dirent.h>
#include <fstream>
#include <cstring>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include<sys/time.h>
#include <map>
#include "acl/acl.h"
#include "acl/ops/acl_dvpp.h"
#include "atlas_utils.h"

#include "opencv2/opencv.hpp"
#include "opencv2/imgcodecs/legacy/constants_c.h"
#include "opencv2/imgproc/types_c.h"


typedef enum DynamicType {
    DYNAMIC_BATCH = 0,
    DYNAMIC_HW = 1
} DynamicType;

typedef struct DynamicInfo {
    uint64_t dynamicArr[2] = {0};
    DynamicType dynamicType = DYNAMIC_BATCH;
} DynamicInfo;


// 存储图像数据的联合体
using Data = union
{
    uint8_t uint8[65536];
    uint16_t uint16[32768];
    uint32_t uint32[16384];
    int16_t int16[32768];
    int32_t int32[16384];
};

// UDP帧的结构
typedef struct
{
    unsigned int head;
    unsigned int len;
    unsigned int id;
    unsigned short seq;
    unsigned short num;
    Data frm_body;
    unsigned int tail;
    unsigned char check;
}UdpFrame;

// Image帧帧头
typedef struct
{
    uint8_t frm_flag[2]={0x5A, 0x4A};
    uint8_t data_len=0x10;
    uint8_t command = 0xEE;
    uint32_t img_id;
    uint16_t img_height;
    uint16_t img_width;
    uint8_t hour;
    uint8_t minute;
    uint8_t second;
    uint8_t fract_second;
    uint8_t reservation1[2]={0};
    uint16_t crc;
}ImageFrameHead;

#define UDP_FRAME_HEAD   0x52445324
#define UPD_FRAME_HEAD_SIZE 4
#define UDP_FRAME_ID     0x5A5A0077
#define UDP_FRAME_TAIL   0x0A0D24


static const unsigned short Crc16FastTable[16] = 
{
    0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
    0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef
};


class time_guard {
public:
    time_guard(std::string name): name_(name) {
        gettimeofday(&begin, NULL);
    }

    // 退出作用域销毁时自动输出
    ~time_guard() {
        gettimeofday(&end, NULL);
        float time_cost = 1000 * (end.tv_sec - begin.tv_sec) + (end.tv_usec - begin.tv_usec) / 1000.000;
        INFO_LOG("%s time: %fms", name_.c_str(), time_cost);
    }

    // 显示的获取
    float get() {
        gettimeofday(&end, NULL);
        return 1000 * (end.tv_sec - begin.tv_sec) + (end.tv_usec - begin.tv_usec) / 1000.000;
    }

private:
    std::string name_;
    struct timeval begin;
    struct timeval end;
};

/**
 * Utils
 */
class Utils {
public:
    /**
    * @brief get width and height of video
    * @param [in] fileFp: file stream
    * @param [in] buffer of input data
    * @param [in] dataSize: size of data
    * @return success or fail
    */
    static bool WriteToFile(FILE *fileFp, void *dataDev, uint32_t dataSize);

    /**
    * @brief check fold, if not exist, create it
    * @param [in] fileName: fold to check
    * @return result
    */
    static Result CheckFolder(const char* foldName);

    static void* CopyDataDeviceToLocal(void* deviceData, uint32_t dataSize);

    static std::string printCurrentTime();

    static Result CopyImageDataToDvpp(ImageData& imageDevice, ImageData srcImage);
    static Result CopyImageDataToDvpp(ImageData& imageDevice, cv::Mat& srcImage);

    static void* CopyDataHostToDvpp(void* data, int size);

    static void* CopyDataDeviceToDvpp(void* data, int size);

    static void* CopyDataHostToDevice(void* deviceData, uint32_t dataSize);
    static void* CopyDataDeviceToDevice(void* deviceData, uint32_t dataSize);
    static void* CopyDataToDevice(void* data, uint32_t dataSize, aclrtMemcpyKind policy);

    static unsigned short Crc16Fast(const unsigned char *ptr, unsigned len, unsigned short initvalue);

    // opencv官方没有提供BGR转YUVNV12的函数
    static void BGR2YUV_nv12(const cv::Mat& src, cv::Mat &dst);

    static cv::Rect2f xywh_cxcywh(const cv::Rect2f& rect);

    static cv::Size2f letterbox_dim(cv::Size img_size, cv::Size box);
    static cv::Mat letterbox_img(const cv::Mat &img, cv::Size input_size);
    static void inv_letterbox_bbox(cv::Rect2f& bbox, cv::Size box_dim, cv::Size img_dim);

    
    static void draw_text(cv::Mat &img, const std::string &str, const cv::Scalar &color, cv::Point pos, bool reverse = false);
    static void draw_bbox(cv::Mat &img, cv::Rect bbox, const std::string &label = "", const cv::Scalar &color = {0, 0, 0});
    static cv::Scalar color_map(int64_t n);

};

